package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.aliyun.iot20180120.Client;
import com.aliyun.iot20180120.models.*;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Lists;
import com.zzyl.base.PageResponse;
import com.zzyl.base.ResponseResult;
import com.zzyl.constant.CacheConstants;
import com.zzyl.dto.DeviceDto;
import com.zzyl.dto.DevicePageQueryDto;
import com.zzyl.dto.DeviceServiceDataPageQueryDto;
import com.zzyl.entity.Device;
import com.zzyl.enums.BasicEnum;
import com.zzyl.enums.DeviceLocationTypeEnum;
import com.zzyl.enums.DevicePhysicalLocationTypeEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.DeviceDataMapper;
import com.zzyl.mapper.DeviceMapper;
import com.zzyl.properties.AliIoTConfigProperties;
import com.zzyl.service.DeviceService;
import com.zzyl.vo.DeviceDataGraphVo;
import com.zzyl.vo.DeviceVo;
import com.zzyl.vo.ProductVo;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


/**
 * @Description DeviceServiceImpl
 * @Author Lwj
 * @Date 2024-09-11-12:23
 */
@Service
@Slf4j
public class DeviceServiceImpl implements DeviceService {

    @Autowired
    private Client client;
    @Autowired
    private AliIoTConfigProperties aliIoTConfigProperties;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private DeviceMapper deviceMapper;
    @Autowired
    private DeviceDataMapper deviceDataMapper;

    /**
     * 从物联网平台同步产品列表
     * 同步数据
     */
    @Override
    public void syncProductList() {
        //请求参数
        QueryProductListRequest queryProductListRequest = new QueryProductListRequest();
        queryProductListRequest.setPageSize(200);
        queryProductListRequest.setCurrentPage(1);
        queryProductListRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        //调用第三方查询产品列表
        QueryProductListResponse queryProductListResponse;
        try {
            queryProductListResponse = client.queryProductList(queryProductListRequest);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_ERROR);
        }
        //判断，如果数据为空，则中断请求
        if (!queryProductListResponse.getBody().success) {
            throw new BaseException(BasicEnum.IOT_LIST_PRODUCT_ERROR);
        }
        //获取数据，存储到redis
        List<ProductVo> productVoList = queryProductListResponse.getBody().getData().getList().getProductInfo().stream().map(p -> BeanUtil.toBean(p, ProductVo.class)).collect(Collectors.toList());
        //存储到redis
        stringRedisTemplate.opsForValue().set(CacheConstants.ALL_PRODUCT_KEY, JSONUtil.toJsonStr(productVoList), 24, TimeUnit.HOURS);
    }

    /**
     * 查询所有产品列表
     */
    @Override
    public List<ProductVo> allProduct() {
        //从缓存中获取数据
        String jsonStr = stringRedisTemplate.opsForValue().get(CacheConstants.ALL_PRODUCT_KEY);
        //如果为空，返回空集合
        if (StrUtil.isEmpty(jsonStr)) {
            return Collections.emptyList();
        }
        //转换数据，并返回
        return JSONUtil.toList(jsonStr, ProductVo.class);
    }

    /**
     * 注册设备
     *
     * @param deviceDto
     */
    @Override
    public void registerDevice(@NotNull DeviceDto deviceDto) {
        //检验设备名称是否重复
        Long count = deviceMapper.countByDeviceName(deviceDto.getDeviceName());
        if (count > 0) {
            throw new BaseException(BasicEnum.DEVICE_NAME_EXIST);
        }
        //iot新增设备
        RegisterDeviceRequest registerDeviceRequest = deviceDto.getRegisterDeviceRequest();
        registerDeviceRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        RegisterDeviceResponse registerDeviceResponse = null;
        try {
            registerDeviceResponse = client.registerDevice(registerDeviceRequest);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }
        //接口是否调通
        if (registerDeviceResponse == null || !registerDeviceResponse.getBody().success) {
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }
        //属性拷贝
        Device device = BeanUtil.copyProperties(deviceDto, Device.class);
        device.setIotId(registerDeviceResponse.getBody().getData().getIotId());
        //产品名称
        QueryProductRequest queryProductRequest = new QueryProductRequest();
        queryProductRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        queryProductRequest.setProductKey(deviceDto.getProductKey());
        QueryProductResponse queryProductResponse = null;
        try {
            queryProductResponse = client.queryProduct(queryProductRequest);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_ERROR);
        }
        //设置产品名称
        if (queryProductResponse.getBody().success) {
            device.setProductName(queryProductResponse.getBody().getData().getProductName());
        }
        //如果设备绑定的位置是随身设备，则把物理绑定位置设置为-1
        //原因是为了后期方便通过位置字段查询老人数据
        if (device.getLocationType().equals(DeviceLocationTypeEnum.PORTABLE_DEVICE.getOrdinal())) {
            device.setPhysicalLocationType(DevicePhysicalLocationTypeEnum.ELDER.getOrdinal());
        }
        //保存设备
        try {
            deviceMapper.insertSelective(device);
        } catch (Exception e) {
            //设备保存失败
            //删除iot中的设备数据
            DeleteDeviceRequest deleteDeviceRequest = new DeleteDeviceRequest();
            deleteDeviceRequest.setDeviceName(device.getDeviceName());
            deleteDeviceRequest.setIotId(device.getIotId());
            deleteDeviceRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
            deleteDeviceRequest.setProductKey(device.getProductKey());
            try {
                client.deleteDevice(deleteDeviceRequest);
            } catch (Exception ex) {
                throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
            }
            throw new BaseException(BasicEnum.RE_SELECT_PRODUCT);
        }
    }

    /**
     * 分页查询
     *
     * @param devicePageQueryDto
     * @return
     */
    @Override
    public PageResponse<DeviceVo> pageQueryDevice(DevicePageQueryDto devicePageQueryDto) {
        PageHelper.startPage(devicePageQueryDto.getPageNum(), devicePageQueryDto.getPageSize());
        Page<DeviceVo> deviceVos = deviceMapper.selectByPage(devicePageQueryDto);
        return PageResponse.of(deviceVos, DeviceVo.class);
    }

    /**
     * 查询设备详细数据
     *
     * @param request 查询设备详情请求模型
     * @return 设备详细数据
     */
    @Override
    public ResponseResult<DeviceVo> queryDeviceDetail(QueryDeviceDetailRequest request) {

        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        QueryDeviceDetailResponse response;
        try {
            response = client.queryDeviceDetail(request);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_ERROR);
        }
        //判断接口是否调通
        if (!response.getBody().getSuccess()) {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_ERROR);
        }

        //查询数据库的数据
        DeviceVo deviceVo = deviceMapper.selectByIotId(response.getBody().getData().getIotId());
        QueryDeviceDetailResponseBody.QueryDeviceDetailResponseBodyData data = response.getBody().getData();
        BeanUtil.copyProperties(data, deviceVo, CopyOptions.create().ignoreNullValue());

        return ResponseResult.success(deviceVo);
    }

    /**
     * 查询指定设备的物模型运行状态
     *
     * @param queryDevicePropertyStatusRequest
     * @return
     */
    @Override
    public ResponseResult queryDevicePropertyStatus(QueryDevicePropertyStatusRequest queryDevicePropertyStatusRequest) {
        queryDevicePropertyStatusRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        QueryDevicePropertyStatusResponse StatusResponse;
        try {
            StatusResponse = client.queryDevicePropertyStatus(queryDevicePropertyStatusRequest);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_PROPERTY_STATUS_ERROR);
        }
        return ResponseResult.success(StatusResponse.getBody().getData());
    }

    /**
     * 查看指定产品的已发布物模型中的功能定义详情
     *
     * @param queryThingModelPublishedRequest
     * @return
     */
    @Override
    public ResponseResult queryThingModelPublished(QueryThingModelPublishedRequest queryThingModelPublishedRequest) {
        queryThingModelPublishedRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        QueryThingModelPublishedResponse response;
        try {
            response = client.queryThingModelPublished(queryThingModelPublishedRequest);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_THING_MODEL_PUBLISHED_ERROR);
        }
        return ResponseResult.success(response.getBody().getData());
    }

    /**
     * 修改设备备注名称
     *
     * @param deviceDto
     */
    @Override
    @Transactional
    public void updateDevice(DeviceDto deviceDto) {
        //检验数据库是否存在设备
        Device dbDevice = deviceMapper.selectByPrimaryKey(deviceDto.getId());
        if (ObjectUtil.isEmpty(dbDevice)) {
            throw new BaseException(BasicEnum.DEVICE_NOT_EXIST);
        }
        // 修改IOT
        BatchUpdateDeviceNicknameRequest request = new BatchUpdateDeviceNicknameRequest();
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo nicknameInfo = BeanUtil.toBean(deviceDto, BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo.class);
        request.setDeviceNicknameInfo(Lists.newArrayList(nicknameInfo));
        BatchUpdateDeviceNicknameResponse response;
        try {
            response = client.batchUpdateDeviceNickname(request);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_BATCH_UPDATE_DEVICE_ERROR);
        }

        // 判断IOT是否修改成功
        if (ObjectUtil.notEqual(Boolean.TRUE, response.getBody().getSuccess())) {
            throw new BaseException(BasicEnum.IOT_BATCH_UPDATE_DEVICE_ERROR);
        }

        //属性拷贝
        Device device = BeanUtil.copyProperties(deviceDto, Device.class);
        //如果是随身设备，物理位置设为-1
        if (device.getLocationType().equals(DeviceLocationTypeEnum.PORTABLE_DEVICE.getOrdinal())) {
            device.setPhysicalLocationType(DevicePhysicalLocationTypeEnum.ELDER.getOrdinal());
        }
        // 修改数据库
        try {
            deviceMapper.updateByPrimaryKeySelective(device);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.RE_SELECT_PRODUCT);
        }
    }

    /**
     * 删除设备
     *
     * @param deleteDeviceRequest
     */
    @Override
    public void deleteDevice(DeleteDeviceRequest deleteDeviceRequest) {
        //封装IotInstanceId
        deleteDeviceRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        DeleteDeviceResponse response;
        try {
            response = client.deleteDevice(deleteDeviceRequest);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
        }
        //判断IOT是否删除设备成功
        if (ObjectUtil.equals(Boolean.TRUE, !response.getBody().getSuccess())) {
            deviceMapper.deleteByIotId(deleteDeviceRequest.getIotId());
            return;
        }
        throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
    }

    /**
     * 分页查询设备服务调用数据
     *
     * @param deviceServiceDataPageQueryDto
     * @return
     */
    @Override
    public ResponseResult pageQueryDeviceServiceData(DeviceServiceDataPageQueryDto deviceServiceDataPageQueryDto) {
        QueryDeviceServiceDataRequest request = new QueryDeviceServiceDataRequest();
        //完善请求数据IotInstanceId、PageSize、IotId、EndTime、StartTime
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        request.setIotId(deviceServiceDataPageQueryDto.getIotId());
        request.setEndTime(deviceServiceDataPageQueryDto.getEndTime());
        request.setStartTime(deviceServiceDataPageQueryDto.getStartTime());
        request.setPageSize(deviceServiceDataPageQueryDto.getPageSize());
        QueryDeviceServiceDataResponse response;
        try {
            response = client.queryDeviceServiceData(request);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_SERVICE_DATA_ERROR);
        }
        //判断iot是否查询成功
        if (!response.getBody().getSuccess()) {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_SERVICE_DATA_ERROR);
        }
        return ResponseResult.success(response.getBody().getData());
    }

    /**
     * 按天统计查询指标数据
     *
     * @param iotId
     * @param functionId
     * @param endTime
     * @param startTime
     * @return
     */
    @Override
    public List<DeviceDataGraphVo> queryDeviceDataListByDay(String iotId, String functionId, Long endTime, Long startTime) {
        //按日聚合数据
        List<DeviceDataGraphVo> deviceDataGraphVoList = deviceDataMapper.queryDeviceDataListByDay(iotId, functionId, LocalDateTimeUtil.of(startTime), LocalDateTimeUtil.of(endTime));
        //构建一个24小时的集合
        List<DeviceDataGraphVo> list = DeviceDataGraphVo.dayInstance(LocalDateTimeUtil.of(startTime));
        //转换为map
        Map<String, Double> map = deviceDataGraphVoList.stream().collect(Collectors.toMap(DeviceDataGraphVo::getDateTime, DeviceDataGraphVo::getDataValue));
        list.forEach(d -> {
            //从map获取值，如果为空，则给默认为0
            Double val = map.get(d.getDateTime()) == null ? 0.0 : map.get(d.getDateTime());
            d.setDataValue(val);
        });
        return list;
    }

    /**
     * 按周统计查询指标数据
     *
     * @param iotId
     * @param functionId
     * @param startTime
     * @param endTime
     * @return
     */
    @Override
    public List<DeviceDataGraphVo> queryDeviceDataListByWeek(String iotId, String functionId, Long startTime, Long endTime) {
        //从数据库查寻本周的所有当天数据的平均值
        List<DeviceDataGraphVo> dataGraphVoList = deviceDataMapper.queryDeviceDataListByWeek(iotId, functionId, LocalDateTimeUtil.of(startTime), LocalDateTimeUtil.of(endTime));
        //构建一个24小时的集合
        List<DeviceDataGraphVo> deviceDataGraphVos = DeviceDataGraphVo.weekInstance(LocalDateTimeUtil.of(startTime));
        //转换为map
        Map<String, Double> doubleMap = dataGraphVoList.stream().collect(Collectors.toMap(DeviceDataGraphVo::getDateTime, DeviceDataGraphVo::getDataValue));
        //遍历dataGraphVoList为其封装数据
        deviceDataGraphVos.forEach(d -> {
            Double val = doubleMap.get(d.getDateTime()) == null ? 0.0 : doubleMap.get(d.getDateTime());
            d.setDataValue(val);
        });
        return deviceDataGraphVos;
    }
}
